﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

namespace THO7AlgoritmTimerApplication
{
    public partial class MainForm : Form
    {
        List<VisionAlgorithm> AlgorithmList = new List<VisionAlgorithm>();
        Stopwatch stopWatch;
        Queue<List<object>> algoritmQueue;


        Bitmap InputImage;
        Bitmap OutputImage;
        public MainForm()
        {
            InitializeComponent();
            AlgorithmList.Add(new VisionAlgorithm_Group_1("Group1"));
            AlgorithmList.Add(new VisionAlgorithm_Group_2("Group2"));
            AlgorithmList.Add(new VisionAlgorithm_Group_3("Group3"));
            AlgorithmList.Add(new VisionAlgorithm_Group_4("Group4"));
            AlgorithmList.Add(new VisionAlgorithm_Group_5("Group5"));
            AlgorithmList.Add(new VisionAlgorithm_Group_6("Group6"));
            AlgorithmList.Add(new VisionAlgorithm_Group_7("Group7"));
            AlgorithmList.Add(new VisionAlgorithm_Group_8("Group8"));
            AlgorithmList.Add(new VisionAlgorithm_Group_9("Group9"));
            AlgorithmList.Add(new VisionAlgorithm_Group_10("Group10"));
            AlgorithmList.Add(new VisionAlgorithm_Group_11("Group11"));
            AlgorithmList.Add(new VisionAlgorithm_Group_12("Group12"));
            AlgorithmList.Add(new VisionAlgorithm_Group_13("Group13"));
            AlgorithmList.Add(new VisionAlgorithm_Group_14("Group14"));
            AlgorithmList.Add(new VisionAlgorithm_Group_15("Group15"));
            AlgorithmList.Add(new VisionAlgorithm_Group_16("Group16"));
            AlgorithmList.Add(new VisionAlgorithm_Group_17("Group17"));
            AlgorithmList.Add(new VisionAlgorithm_Group_18("Group18"));
            AlgorithmList.Add(new VisionAlgorithm_Group_19("Group19"));
            AlgorithmList.Add(new VisionAlgorithm_Group_20("Group20"));
            AlgorithmList.Add(new VisionAlgorithm_Group_21("Group21"));
            AlgorithmList.Add(new VisionAlgorithm_Group_22("Group22"));
            AlgorithmList.Add(new VisionAlgorithm_Group_23("Group23"));
            AlgorithmList.Add(new VisionAlgorithm_Group_24("Group24"));
            AlgorithmList.Add(new VisionAlgorithm_Group_25("Group25"));

            //Insert new Algorithms here
            /*          ^
            *          /|\
            *           |
            */
            foreach (VisionAlgorithm vA in AlgorithmList)
            {
                AlgoListBox.Items.Add(vA.Name);
            }
            algoritmQueue = new Queue<List<object>>();
        }

        private void openPictureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openImage();
        }
        private void openImage()
        {
            OpenFileDialog oFD = new OpenFileDialog();
            oFD.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
            oFD.Filter = "Image Files(*.BMP;*.JPG;*.JPEG;*.PNG;)|*.BMP;*.JPG;*.JPEG;*.PNG;";
            oFD.FilterIndex = 1;
            oFD.RestoreDirectory = true;
            if (oFD.ShowDialog() == DialogResult.OK)
            {
                String CurrentFileName = Path.GetFullPath(oFD.FileName);
                InputImage = new Bitmap(CurrentFileName);
                InputPictureBox.Image = InputImage;
            }
        }

        private void AlgoListBox_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void AlgoButton_Click(object sender, EventArgs e)
        {

            if (InputImage != null)
            {
                try
                {
                    if (!textBoxRuns.Text.Equals("") && Convert.ToInt32(textBoxRuns.Text) > 0)
                    {
                        InfoLabel.Text = "";
                        foreach (VisionAlgorithm vA in AlgorithmList)
                        {
                            algoritmQueue.Enqueue(new List<object> { vA, InputImage, Convert.ToInt32(textBoxRuns.Text) });

                        }
                        runQueuedAlgorithms();
                    }
                    
                }
                catch (FormatException fe)
                {
                    InfoLabel.Text += "Can't run that number of times\n";
                }
            }

        }

        private bool runQueuedAlgorithms()
        {
            if (algoritmQueue.Count > 0)
            {
                List<object> algArgs = algoritmQueue.Dequeue();
                InfoLabel.Text += "Start running " + ((VisionAlgorithm)(algArgs.ElementAt(0))).Name + "...\n";
                startAlgThread(algArgs);
                return true;
            }
            return false;
        }

        private void OutputPictureBox_DoubleClick(object sender, EventArgs e)
        {
            if (OutputPictureBox.Image != null)
            {
                Form ipForm = new ImagePreviewForm(new Bitmap(OutputPictureBox.Image));
                ipForm.Show();
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void OutputToInputButton_Click(object sender, EventArgs e)
        {
            if (OutputPictureBox.Image != null)
            {
                InputImage = new Bitmap(OutputPictureBox.Image);
                InputPictureBox.Image = InputImage;
                OutputPictureBox.Image = null;
            }
        }

        private void ClearButton_Click(object sender, EventArgs e)
        {
            InfoLabel.Text = "";
        }

        private void backgroundAlgorithmWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show("Error: " + e.Error.Message);
            }
            else if (e.Cancelled)
            {
                InfoLabel.Text += "...Cancelled\n";
            }
            else
            {                
                double elapsedms = Convert.ToDouble(stopWatch.ElapsedMilliseconds);
                double average = elapsedms / Convert.ToDouble(textBoxRuns.Text);

                InfoLabel.Text += e.Result + ", took: " + elapsedms + " ms over " + textBoxRuns.Text + " times\n";
                InfoLabel.Text += "==> average: " + average + "ms\n";
                OutputPictureBox.Image = OutputImage;
                if (checkBoxSaveOutputImages.Checked)
                {
                    OutputImage.Save(e.Result.ToString()+".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
                }
            }
            if (!runQueuedAlgorithms())
            {
                DateTime current = DateTime.Now;
                String curStr = current.ToString("yyyy-MM-dd__HH-mm-ss");
                String fileName = curStr + "_results.txt";
                FileStream fs = new FileStream(fileName, FileMode.Create);
                StreamWriter outfile = new StreamWriter(fs,Encoding.UTF8);
                outfile.Write(InfoLabel.Text.ToString());
                outfile.Flush();
                outfile.Close();
                fs.Close();
                EnableAllInputs(true);
                MessageBox.Show("Done...\nResults saved to: " + fileName);
            }
        }

        private void backgroundAlgorithmWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            System.ComponentModel.BackgroundWorker worker;
            worker = (System.ComponentModel.BackgroundWorker)sender;
            List<object> argList = (List<object>)e.Argument;
            VisionAlgorithm visAlg = (VisionAlgorithm) argList.ElementAt(0);
            Bitmap InputImage = (Bitmap)argList.ElementAt(1);
            int numberOfRuns = (int)argList.ElementAt(2);
            stopWatch.Start();
            try
            {

                for (int i = 1; i < numberOfRuns; i++)
                {
                    visAlg.DoAlgorithm(InputImage);
                }
                OutputImage = visAlg.DoAlgorithm(InputImage);
                e.Result = visAlg.Name + " finished successfully";
            }
            catch (NotImplementedException nie)
            {
                e.Cancel = true;
            }
            finally
            {
                stopWatch.Stop();
            }

        }

        private void EnableAllInputs(bool state)
        {
            openPictureToolStripMenuItem.Enabled = state;
            AlgoButton.Enabled = state;
            AlgoListBox.Enabled = state;
            OutputToInput.Enabled = state;
            InputPictureBox.Enabled = state;
            textBoxRuns.Enabled = state;
        }

        private void startAlgThread(List<object> argList)
        {
            stopWatch = new Stopwatch();
            EnableAllInputs(false);
            backgroundAlgorithmWorker.RunWorkerAsync(argList); 
        }

        private void InfoGroupBox_Enter(object sender, EventArgs e)
        {

        }
    }
}
